<template>
    <van-sticky>
        <van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft">
            <template #right>
                <span @click="onClickRight" style="color: #1989FA;" v-if="!isDisabled">提交</span>
            </template>
        </van-nav-bar>
    </van-sticky>
    <div style="margin-top: 0.5rem;">
        <van-cell-group inset>
            <van-cell title="任务附件" is-link @click="showFileList()" />
        </van-cell-group>
    </div>
    <div v-if="loading" v-for="i in 10" :key="i" style="margin-top: 0.5rem;">
        <van-cell-group inset class="skeleton-group">
            <van-skeleton-paragraph row-width="90%" class="skeleton-item" />
        </van-cell-group>
    </div>
    <div v-for="(item, index) in allCheckData" :key="index" :title="item">
        <van-cell-group inset
            :class="{ 'finish-normal': checkIfFinishNormal(item), 'finish-abnormal': checkIfFinishAbnormal(item) }"
            @click="handleCellClick(index)">
            <van-row class="row-container">
                <van-col span="16" class="title-col"
                    :class="{ 'finish-normal': checkIfFinishNormal(item), 'finish-abnormal': checkIfFinishAbnormal(item) }">
                    {{ item.name }}
                </van-col>
                <van-col span="8" class="button-col">
                    <van-button type="success" :plain="allCheckData[index].status !== '正常'" size="small"
                        @click.stop="handleActionClick(index, '正常')" :disabled="isDisabled">
                        正常
                    </van-button>
                    <van-button type="danger" :plain="allCheckData[index].status !== '异常'" size="small"
                        @click.stop="handleActionClick(index, '异常')" :disabled="isDisabled">
                        异常
                    </van-button>
                </van-col>
            </van-row>
            <div v-if="requirement.type.includes('数据') && expandedIndex === index" class="data-container">
                <van-col span="24" class="data-col">
                    <div v-for="(text, textIndex) in requirement.field" :key="textIndex">
                        <van-field :label="text" :placeholder="requirement.count === 1
                            ? `请输入${text}数据`
                            : `请输入${text}第${currentGroup[index] + 1}组数据`" class="data-field"
                            v-model="allCheckData[index].groupData[currentGroup[index]][textIndex]" @click.stop
                            :readonly="isDisabled" />
                    </div>
                </van-col>
                <div class="group-buttons-container" v-if="requirement.count > 1">
                    <div class="group-buttons-row">
                        <van-button type="primary" class="group-button prev" @click.stop="handlePrevGroup(index)"
                            :disabled="currentGroup[index] <= 0">
                            上一组
                        </van-button>
                        <van-button type="primary" class="group-button next" @click.stop="handleNextGroup(index)"
                            :disabled="currentGroup[index] >= requirement.count - 1">
                            下一组
                        </van-button>
                    </div>
                </div>
            </div>
            <div class="data-container"
                v-if="requirement.type.includes('图片') && allCheckData[index].status === '正常' && expandedIndex === index">
                <van-row @click.stop>
                    <van-col span="24" class="upload-col">
                        <van-uploader v-model="allCheckData[index].normalImages" :multiple="true" accept="image/*"
                            :preview-full-image="false"
                            @click-preview="(file) => handlePreviewImage(allCheckData[index].normalImages, file)"
                            :disabled="isDisabled" :before-read="handleBeforeRead" />
                    </van-col>
                </van-row>
            </div>
            <div class="data-container"
                v-if="requirement.type.includes('图片') && allCheckData[index].status === '异常' && expandedIndex === index">
                <van-row @click.stop>
                    <van-field label="异常描述" class="error-field" v-model="allCheckData[index].errorRemarks"
                        placeholder="请输入异常描述" :readonly="isDisabled" />
                    <van-col span="24" class="upload-col">
                        <van-uploader v-model="allCheckData[index].errorImages" :multiple="true" accept="image/*"
                            :preview-full-image="false"
                            @click-preview="(file) => handlePreviewImage(allCheckData[index].errorImages, file)"
                            :disabled="isDisabled" :before-read="handleBeforeRead" />
                    </van-col>
                </van-row>
            </div>
        </van-cell-group>
    </div>
    <FileList ref="FileListRef" :title="attachmentTitle" :attachments="attachmentData">
    </FileList>
</template>
<script setup>
import { ref, watch, onMounted, onUnmounted, computed, nextTick } from 'vue';
import { showImagePreview, showConfirmDialog, showToast, showLoadingToast, closeToast, showSuccessToast, showFailToast } from 'vant';
import { base64ToObjectUrl, base64ToFile } from '@/utils/Misc.js';
import zxlzAPI from '@/api/zxlz';
import FileList from '@/components/FileList.vue';
import fileAPI from '@/api/file.js';
import db from "@/utils/Dexie.js";
import { Watermark } from '@/utils/Watermark.js';
import { errorNotify } from "@/utils/Misc";
import { useRouter } from 'vue-router'
import useStore from '@/store/index';
const router = useRouter();
const store = useStore();
const title = ref("任务执行");
const list = ref([]);
const requirement = ref({})
const files = ref([]);
const expandedIndex = ref(-1);
const allCheckData = ref([]);
const currentGroup = ref([]);
const loading = ref(false);
const FileListRef = ref(null);
const attachmentTitle = ref("");
const attachmentData = ref([]);
const isDisabled = computed(() => {
    const status = new URLSearchParams(window.location.search).get("status");
    return status === "已完成" || status === "归档";
});
onUnmounted(() => {
    allCheckData.value.forEach(item => {
        item.normalImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
        item.errorImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
    });
});
onMounted(async () => {
    await loadFromIndexedDB();
});
const onClickLeft = () => {
    router.back();
}
const onClickRight = async () => {
    handleSubmit();
};
const handleBeforeRead = async (file) => {
    if (Array.isArray(file)) {
        return Promise.all(file.map(handleBeforeRead));
    }
    try {
        return await Watermark.addWatermarkToImage(file);
    } catch (error) {
        showToast('图片添加水印失败，请重试');
        return false;
    }
};
const getZxTaskFormSubmitDtoList = async () => {
    for (const item of allCheckData.value) {
        const needCheckData = requirement.value.type.includes('数据');
        const needCheckImage = requirement.value.type.includes('图片');
        if (item.status === '异常') {
            if (!item.errorRemarks || item.errorRemarks.trim() === '') {
                showFailToast({ message: '表单未填写\n完成' });
                throw new Error('表单未填写\n完成');
            }
        }
        if (needCheckData) {
            const isValueComplete = () => {
                if (!item.groupData || !Array.isArray(item.groupData)) return false;
                for (const secondLevel of item.groupData) {
                    if (!Array.isArray(secondLevel)) return false;
                    for (const lastLevelItem of secondLevel) {
                        if (lastLevelItem === '') return false;
                    }
                }
                return true;
            };
            if (!isValueComplete()) {
                showFailToast({ message: '表单未填写\n完成' });
                throw new Error('表单未填写\n完成');
            }
        }
        if (needCheckImage) {
            const hasImages = (item.status === '正常' && item.normalImages && item.normalImages.length > 0) ||
                (item.status === '异常' && item.errorImages && item.errorImages.length > 0);
            if (!hasImages) {
                showFailToast({ message: '表单未填写\n完成' });
                throw new Error('表单未填写\n完成');
            }
        }
        if (item.status !== '正常' && item.status !== '异常') {
            showFailToast({ message: '表单未填写\n完成' });
            throw new Error('表单未填写\n完成');
        }
    }
    for (const item of allCheckData.value) {
        const processImages = async (images) => {
            if (!images || !Array.isArray(images)) return;
            for (const image of images) {
                if (!image.imageId && 'content' in image) {
                    try {
                        const prefixMatch = image.content.match(/data:image\/([^;]+);/);
                        const suffix = prefixMatch?.[1] || 'png';
                        const timestamp = Date.now();
                        const mimeType = `image/${suffix}`;
                        const fileName = `${timestamp}.${suffix}`;
                        const file = base64ToFile(image.content, fileName, mimeType);
                        const formData = new FormData();
                        formData.append('file', file);
                        uploadedImages.value++;
                        loadingToastText.value = `正在上传图片 ${uploadedImages.value}/${totalImages.value}`;
                        const res = await fileAPI.uploadFile(formData);
                        image.imageId = res.data.sysFile.id;
                    } catch (error) {
                        errorNotify("RenWuDetail.vue", "getZxTaskFormSubmitDtoList-processImages", error);
                        throw error;
                    }
                }
            }
        };
        await processImages(item.normalImages);
        await processImages(item.errorImages);
    }
    const zxTaskFormSubmitDtoList = allCheckData.value.map(item => {
        const allImageIds = [];
        if (item.normalImages && Array.isArray(item.normalImages)) {
            item.normalImages.forEach(img => {
                if (img.imageId) allImageIds.push(img.imageId);
            });
        }
        if (item.errorImages && Array.isArray(item.errorImages)) {
            item.errorImages.forEach(img => {
                if (img.imageId) allImageIds.push(img.imageId);
            });
        }
        return {
            "id": item.id,
            "isFinish": 1,
            "value": item.groupData ? JSON.stringify(item.groupData) : "",
            "imageIds": allImageIds.join(','),
            "isAbnormal": item.status === "异常" ? 1 : 0,
            "abnormalRemark": item.errorRemarks || ""
        };
    });
    return zxTaskFormSubmitDtoList;
};
const loadingToastText = ref("数据提交中...");
const totalImages = ref(0);
const uploadedImages = ref(0);
const handleSubmit = async () => {
    totalImages.value = 0;
    uploadedImages.value = 0;
    allCheckData.value.forEach(item => {
        if (item.normalImages && Array.isArray(item.normalImages)) {
            totalImages.value += item.normalImages.filter(img => 'content' in img && !img.imageId).length;
        }
        if (item.errorImages && Array.isArray(item.errorImages)) {
            totalImages.value += item.errorImages.filter(img => 'content' in img && !img.imageId).length;
        }
    });
    showLoadingToast({
        message: loadingToastText,
        forbidClick: true,
        duration: 0
    });
    if (totalImages.value === 0) {
        loadingToastText.value = "数据提交中...";
    } else {
        loadingToastText.value = `正在上传 ${totalImages.value} 张图片...`;
    }
    const id = new URLSearchParams(window.location.search).get('id');
    const zxTaskFormSubmitDtoList = await getZxTaskFormSubmitDtoList();
    const submifForm = {
        id: id,
        zxTaskFormSubmitDtoList: zxTaskFormSubmitDtoList
    };
    loadingToastText.value = "数据提交中...";
    zxlzAPI.submitTaskForm(submifForm).then(res => {
        db.zxlzCache.where('id').equals(id).delete();
        closeToast();
        showSuccessToast('提交成功！');
        router.push("/home");
    }).catch(error => {
        errorNotify("Execute.vue", "handleSubmit", error);
        closeToast();
        showFailToast(error);
    });
};
watch(
    allCheckData,
    async (newVal) => {
        await saveToIndexedDB();
    },
    { deep: true }
);
const saveToIndexedDB = async () => {
    const id = new URLSearchParams(window.location.search).get("id")
    try {
        const cacheItem = await db.zxlzCache
            .where("id")
            .equals(id)
            .first()
        const pureData = JSON.parse(JSON.stringify(allCheckData.value));
        const pureRequirement = JSON.parse(JSON.stringify(requirement.value));
        const pureFiles = JSON.parse(JSON.stringify(files.value));
        await db.zxlzCache.put({ id: id, detail: cacheItem["detail"], data: pureData, requirement: pureRequirement, files: pureFiles });
    } catch (error) {
        errorNotify("Execute.vue", "saveToIndexedDB", error);
    }
};
const loadFromIndexedDB = async () => {
    loading.value = true;
    try {
        const id = new URLSearchParams(window.location.search).get("id");
        const cacheData = await db.zxlzCache.get(id);
        if (cacheData && cacheData.data) {
            requirement.value = cacheData.requirement;
            files.value = cacheData.files;
            allCheckData.value = JSON.parse(JSON.stringify(cacheData.data));
            allCheckData.value.forEach(item => {
                item.normalImages = item.normalImages.map(image => {
                    if (!image.content) {
                        return { ...image };
                    }
                    return {
                        ...image,
                        objectUrl: base64ToObjectUrl(image.content, image.type)
                    };
                });
                item.errorImages = item.errorImages.map(image => {
                    if (!image.content) {
                        return { ...image };
                    }
                    return {
                        ...image,
                        objectUrl: base64ToObjectUrl(image.content, image.type)
                    };
                });
            });
            list.value = allCheckData.value.map(item => item.name);
            initGroupData();
            loading.value = false;
        } else {
            getEquipmentData();
        }
    } catch (error) {
        errorNotify("Execute.vue", "loadFromIndexedDB", error);
        loading.value = false;
    }
};
const getEquipmentData = async () => {
    window.scrollTo(0, 0);
    loading.value = true;
    expandedIndex.value = -1;
    const id = new URLSearchParams(window.location.search).get("id");
    zxlzAPI.getTaskFormById(id).then(res => {
        list.value = res.data.zxTaskTableView.zxTaskFormItemViewList;
        requirement.value = JSON.parse(res.data.zxTaskTableView.requirement);
        files.value = res.data.zxTaskTableView.taskFileList;
        allCheckData.value = list.value.map(item => {
            const status = item.isAbnormal ? "异常" : item.isFinish ? "正常" : null;
            const images = item.imageIds?.split(",").map(id => ({ imageId: id.trim() })) || [];
            return {
                id: item.id,
                name: item.equipmentName + item.unit,
                status: status,
                normalImages: status === "正常" ? images : [],
                errorImages: status === "异常" ? images : [],
                groupData: JSON.parse(item.value),
                errorRemarks: item.abnormalRemark,
            };
        });
        allCheckData.value.sort((a, b) => {
            return a.name.localeCompare(b.name, undefined, {
                numeric: true,
                sensitivity: 'base'
            });
        });
        loading.value = false;
        initGroupData()
    }).catch((error) => {
        errorNotify("Execute.vue", "getEquipmentData", error);
    })
};
const initGroupData = () => {
    const { count, field } = requirement.value;
    if (!count || count <= 0 || !Array.isArray(field) || field.length === 0) return;
    allCheckData.value.forEach((item) => {
        const isGroupDataValid = item.groupData
            && Array.isArray(item.groupData)
            && item.groupData.length === count
            && item.groupData.every(group => Array.isArray(group) && group.length === field.length);
        if (!isGroupDataValid) {
            item.groupData = Array.from({ length: count }, () => Array(field.length).fill(''));
        }
    });
    if (currentGroup.value.length !== allCheckData.value.length) {
        currentGroup.value = allCheckData.value.map(() => 0);
    }
};
const handlePreviewImage = (images, file) => {
    const index = images.findIndex(img => img.imageId === file.imageId);
    if (index === -1) {
        return;
    }
    const hasObjectUrl = 'objectUrl' in file;
    if (hasObjectUrl) {
        const imageUrls = images.map(img => img.objectUrl);
        showImagePreview({
            images: imageUrls,
            startPosition: index,
            closeable: true
        });
    } else {
        showLoadingToast({
            message: '加载数据中...',
            forbidClick: true,
            duration: 0
        });
        fileAPI.downloadFile(file.imageId).then(res => {
            closeToast();
            const blob = res.data;
            const filename = res.headers["content-disposition"].split("filename=")[1];
            const subfix = filename.split(".").pop();
            const reader = new FileReader();
            reader.onloadend = () => {
                let base64Str = reader.result;
                if (base64Str.startsWith('data:application/octet-stream;base64,')) {
                    base64Str = base64Str.replace('data:application/octet-stream;base64,', 'data:image/' + subfix + ';base64,');
                }
                const objectUrl = base64ToObjectUrl(base64Str)
                const newImageData = {
                    ...file,
                    content: base64Str,
                    objectUrl: objectUrl,
                };
                if (index !== -1) {
                    images.splice(index, 1, newImageData);
                }
                showImagePreview({
                    images: images.map(img => img.objectUrl),
                    startPosition: index,
                    closeable: true
                });
            };
            reader.readAsDataURL(blob);
        }).catch((error) => {
            errorNotify("Execute.vue", "handlePreviewImage", error);
        })
    }
};
const showFileList = () => {
    attachmentTitle.value = "任务";
    attachmentData.value = files.value;
    FileListRef.value.showFileList();
};
const checkIfAllFinish = (item) => {
    const needCheckData = requirement.value.type.includes('数据');
    const needCheckImage = requirement.value.type.includes('图片');
    const isDataComplete = () => {
        if (!needCheckData) return true;
        if (!item.groupData || !Array.isArray(item.groupData)) return false;
        return item.groupData.every(secondLevel =>
            Array.isArray(secondLevel) &&
            secondLevel.every(lastLevelItem =>
                lastLevelItem !== null &&
                lastLevelItem !== undefined &&
                (typeof lastLevelItem !== 'string' || lastLevelItem.trim() !== '')
            )
        );
    };
    const isImageComplete = () => {
        if (!needCheckImage) return true;
        if (item.status === '正常') {
            return item.normalImages && item.normalImages.length > 0;
        }
        if (item.status === '异常') {
            const hasValidImages = item.errorImages && item.errorImages.length > 0;
            const hasValidRemark = item.errorRemarks && item.errorRemarks.trim() !== '';
            return hasValidImages && hasValidRemark;
        }
        return false;
    };
    const hasValidStatus = item.status === '正常' || item.status === '异常';
    return hasValidStatus && isDataComplete() && isImageComplete();
};
const checkIfFinishNormal = (item) => {
    return item.status === '正常' && checkIfAllFinish(item);
};
const checkIfFinishAbnormal = (item) => {
    return item.status === '异常' && checkIfAllFinish(item);
};
const handlePrevGroup = (index) => {
    if (currentGroup.value[index] > 0) {
        currentGroup.value[index]--;
    }
};
const handleNextGroup = (index) => {
    if (currentGroup.value[index] < requirement.value.count - 1) {
        currentGroup.value[index]++;
    }
};
const handleCellClick = (index) => {
    if (expandedIndex.value === index) {
        expandedIndex.value = -1;
    } else if (allCheckData.value[index].status) {
        expandedIndex.value = index;
    }
}
const handleActionClick = async (index, action) => {
    const needConfirm = allCheckData.value[index].status !== null
        && allCheckData.value[index].status !== action
        && (allCheckData.value[index].normalImages?.length > 0 || allCheckData.value[index].errorImages?.length > 0);
    if (needConfirm) {
        try {
            await showConfirmDialog({
                title: '警告',
                message: '当前状态已上传照片，确认切换照片将丢失。',
            });
        } catch (error) {
            return;
        }
    }
    if (allCheckData.value[index].status === action) {
        allCheckData.value[index].status = null;
        allCheckData.value[index].normalImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
        allCheckData.value[index].errorImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
        allCheckData.value[index].normalImages = [];
        allCheckData.value[index].errorImages = [];
        expandedIndex.value = -1;
    } else {
        allCheckData.value[index].status = action;
        if (action === '正常') {
            allCheckData.value[index].errorImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
            allCheckData.value[index].errorImages = [];
        } else {
            allCheckData.value[index].normalImages.forEach(img => URL.revokeObjectURL(img.objectUrl));
            allCheckData.value[index].normalImages = [];
        }
        expandedIndex.value = index;
    }
};
</script>
<style scoped>
.finish-normal {
    border-color: #07C160 !important;
}

.finish-abnormal {
    border-color: #EE0A24 !important;
}

.title-col.finish-normal {
    color: #07C160 !important;
    font-weight: bold !important;
}

.title-col.finish-abnormal {
    color: #EE0A24 !important;
    font-weight: bold !important;
}

:deep(.van-cell-group) {
    border: 1px solid #eee;
    margin-bottom: 0.5rem;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    cursor: pointer;
    transition: all 0.3s ease;
    background-color: #ffffff;
}

:deep(.van-cell-group.inset) {
    margin-bottom: 0.5rem;
}

:deep(.van-cell-group):active {
    transform: translateY(1px);
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
}

.row-container {
    display: flex;
    align-items: center;
    min-height: 50px;
}

.title-col {
    font-weight: bold;
    padding-left: 1.2rem;
    transition: color 0.3s ease;
}

.button-col {
    padding-right: 1.2rem;
    text-align: right;
}

:deep(.van-button) {
    margin-left: 4px;
}

:deep(.van-button:first-child) {
    margin-left: 0;
}

.data-container {
    padding: 0 1.2rem 0 1rem;
}

.data-col {
    padding: 0.5rem 0;
}

.data-field {
    border: 1px solid #eee;
}

.error-field {
    border: 1px solid #eee;
    margin-bottom: 0.5rem;
}

:deep(.van-uploader) {
    margin-top: 0.5rem;
}

:deep(.van-uploader__preview-image) {
    width: 80px;
    height: 80px;
    margin-right: 8px;
}

.group-buttons-container {
    width: 100%;
    padding-bottom: 0.5rem;
}

.group-buttons-row {
    display: flex;
    width: 100%;
    margin-bottom: 0.5rem;
}

.group-buttons-row:last-child {
    margin-bottom: 0;
}

.group-button {
    flex: 1;
    margin: 0 4px;
}

.group-button.prev {
    margin-left: 0;
}

.group-button.next {
    margin-right: 0;
}

.skeleton-group .skeleton-item {
    margin: 1.2rem;
}
</style>
